import EventEmitter from 'events'
import fs from 'fs'
class WriteStream extends EventEmitter {
    constructor(path, options) {
        super();
        this.path = path;
        this.flags = options.flags || 'w';
        this.emitClose = options.emitClose || true
        this.highWaterMark = options.highWaterMark || 16 * 1024
        this.start = options.start || 0;
        this.needDrain = false
        this.open();
        this.len = 0;
        this.writing = false;
        this.queue = []; // 内部采用的链表
        this.offset = this.start
    }
    destroy(err) {
        if (typeof this.fd === 'number') {
            fs.close(this.fd, () => this.emit('close'))
        }
        if (err) {
            this.emit("error", err);
        }
    }
    open() {
        fs.open(this.path, this.flags, (err, fd) => {
            if (err) {
                return this.destroy(err);
            }
            this.fd = fd; // 文件打开后 会有fd属性
            this.emit("open", fd);
        });
    }
    _write(chunk, clearQueue) {
        if (typeof this.fd !== 'number') {
            return this.once('open', () => this._write(chunk, clearQueue))
        }
        fs.write(this.fd, chunk, 0, chunk.length, this.offset, (err, written) => {
            this.offset += written;
            this.len -= written
            clearQueue();
        })
    }
    // 将异步操作 转化成串行操作
    write(chunk = '', callback = () => { }) { // 1.像内存中写入  2.像文件中写入
        // chunk  string || buffer
        chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
        this.len += chunk.length;
        let returnValue = this.len < this.highWaterMark
        this.needDrain = !returnValue; // 返回的是false 就需要触发drain事件
        const clearQueue = () => {
            // 清空缓存
            let cacheObj = this.queue.shift();
            if (cacheObj) {
                this._write(cacheObj.chunk, () => {
                    cacheObj.callback()
                    clearQueue();
                });
            } else {
                this.writing = false;
                if (this.needDrain) {
                    this.needDrain = false;
                    this.emit('drain');
                }
            }
        }
        if (!this.writing) {
            // 像文件中写入
            this.writing = true
            this._write(chunk, () => {
                callback()
                clearQueue();
            });
        } else {
            // 像内存中写入
            this.queue.push({
                chunk,
                callback
            })
        }
        return returnValue

    }
}

function createWriteStream(path, options = {}) {
    return new WriteStream(path, options)
}


export {
    createWriteStream
}